package com.atguigu.gmall.gateway.filter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.atguigu.gmall.common.result.Result;
import com.atguigu.gmall.common.result.ResultCodeEnum;
import com.atguigu.gmall.common.util.IpUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.List;

@Component // 注入到spring 容器中.
public class AuthGlobalFilter implements GlobalFilter {

    //  获取配置文件中的控制器. trade.html,myOrder.html,list.html
    @Value("${authUrls.url}")
    private String authUrls;

    @Autowired
    private RedisTemplate redisTemplate;

    //  声明一个对象.
    private AntPathMatcher antPathMatcher = new AntPathMatcher();

    /**
     * 过滤 网关
     * @param exchange
     * @param chain
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //  获取请求：
        ServerHttpRequest request = exchange.getRequest();
        System.out.println(request.getURI());
        String path = request.getURI().getPath();

        //  路径格式匹配.
        if (antPathMatcher.match("/**/inner/**", path)) {
            //  获取响应对象
            ServerHttpResponse response = exchange.getResponse();
        //  返回信息提示.
        return out(response, ResultCodeEnum.PERMISSION);
    }

        //获取到用户id
        String userId = this.getUsrId(request);

        //  获取临时用户Id
        String userTempId = this.getUserTempId(request);

        //  如果用户Id 为 -1
        if ("-1".equals(userId)){
            //  获取响应对象
            ServerHttpResponse response = exchange.getResponse();
            //  返回信息提示.
            return out(response, ResultCodeEnum.PERMISSION);
        }

        //判断
        if (antPathMatcher.match("/api/**/auth/**", path)) { // 符合规则
            if (StringUtils.isEmpty(userId)) { // 用户Id为空.
                //  获取响应对象
                ServerHttpResponse response = exchange.getResponse();
                //  返回信息提示.
                return out(response, ResultCodeEnum.LOGIN_AUTH);
            }
        }

        //对配置文件中的url 控制器进行分割
        // 将多个控制器进行分割
        String[] split = authUrls.split(",");
        if (split != null && split.length > 0) {
            for (String url : split) {
                //判断Path中 是否包含url中的控制器
                //找到会返回对应的下标位置
                if (path.indexOf(url) != -1 && StringUtils.isEmpty(userId)) {
                    //  做页面提示跳转到 登录页面。
                    //  获取响应对象
                    ServerHttpResponse response = exchange.getResponse();
                    //设置重定参数
                    response.setStatusCode(HttpStatus.SEE_OTHER);
                    //设置重定向到哪里
                    response.getHeaders().set(HttpHeaders.LOCATION, "http://passport.gmall.com/login.html?originUrl=" + request.getURI());
                    //重定向
                    return response.setComplete();

                }
            }
        }

        //判断 网关请求头
        if (!StringUtils.isEmpty(userId) || !StringUtils.isEmpty(userTempId)) {
            if (!StringUtils.isEmpty(userId)){
                //  需要将用户Id 存储到请求头中， 然后在后台各个微服务中获取就可以了
                request.mutate().header("userId", userId).build();
            }
            if (!StringUtils.isEmpty(userTempId)){
                request.mutate().header("userTempId", userTempId).build();
            }
            //  将request ---> exchange
            return chain.filter(exchange.mutate().request(request).build());
        }
        //默认返回
        return chain.filter(exchange);
    }

    /**
     * 创建临时用户Id
     * @param request
     * @return
     */
    private String getUserTempId(ServerHttpRequest request) {
        //  获取临时用户Id 并返回临时用户Id；
        String userTempId = "";
        //  还有一个地方，登录按钮： 如果cookie 中有临时用户Id ，将临时用户Id 也放入了header 中.
        List<String> stringList = request.getHeaders().get("userTempId");
        if (!CollectionUtils.isEmpty(stringList)){
            userTempId =  stringList.get(0);
        }else {
            //  点击加入购物车时，将临时用户Id  存储到了cookie 中.
            HttpCookie httpCookie = request.getCookies().getFirst("userTempId");
            if (httpCookie!=null){
                userTempId = httpCookie.getValue();
            }
        }
        //  返回临时用户Id
        return userTempId;
    }

    /**
     * 获取用户名Id
     * @param request
     * @return
     */
    private String getUsrId(ServerHttpRequest request) {
        //  用户Id 从缓存中， 要想从缓存中获取数据，则必须要组成缓存的key！
        String token = "";
        List<String> stringList = request.getHeaders().get("token");
        if (!CollectionUtils.isEmpty(stringList)) {
            token = stringList.get(0);
        } else {
            HttpCookie httpCookie = request.getCookies().getFirst("token");
            if (httpCookie != null) {
                token = httpCookie.getValue();

            }
        }
        //  判断token 是否为空。 用户根本就没有登录过，token 一定为空.
        if (!StringUtils.isEmpty(token)) {
            //组成缓存的key
            String key = "usert:login:" + token;
            //从缓存中获取数据
            String strJson = (String) this.redisTemplate.opsForValue().get(key);
            //  这个字符串原本是 JSONObject
            JSONObject jsonObject = JSONObject.parseObject(strJson);
            //获取缓存中的ip
            String ip = (String) jsonObject.get("ip");
            String currentIp = IpUtil.getGatwayIpAddress(request);
            //  判断ip 一致性。
            if (ip.equals(currentIp)) {
                String userId = (String) jsonObject.get("userId");
                //  返回用户Id
                return userId;
            } else {
                return "-1";
            }
        }
        //  默认返回空字符串
        return "";
    }

    /**
     * 用户信息提示.
     * @param response
     * @param resultCodeEnum
     * @return
     */
    private Mono<Void> out(ServerHttpResponse response, ResultCodeEnum resultCodeEnum) {
        //  给用户友好提示.
        Result<Object> result = Result.build(null, resultCodeEnum);
        //先将result变成字符串
        String str = JSON.toJSONString(result);
        //  获取到了数据流. 输入页面信息时有中文.
        DataBuffer wrap = response.bufferFactory().wrap(str.getBytes());
        // 设置请求头
        response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        // 页面要如何输入数据
        return response.writeWith(Mono.just(wrap));

    }
}
